Skip to content

Suggest mode 6b: Capture and apply block-insert-after suggestions (mechanism)#77971

Open
adamsilverstein wants to merge 10 commits into
suggest-mode-6a-remove-uifrom
suggest-mode-6b-insert-mechanism
Open

Suggest mode 6b: Capture and apply block-insert-after suggestions (mechanism)#77971
adamsilverstein wants to merge 10 commits into
suggest-mode-6a-remove-uifrom
suggest-mode-6b-insert-mechanism

Conversation

@adamsilverstein

@adamsilverstein adamsilverstein commented May 5, 2026

Copy link
Copy Markdown
Member

What

Adds the data-layer mechanism for block-insert-after suggestions (#77434, task 6b). In Suggest mode an inserted block stays at its position but is tagged with metadata.suggestion = { type: 'pending-insert' }. Auto-save persists the marker as a block-insert-after operation; Apply clears the marker; Reject runs removeBlock to undo.

Visual treatment lands in the next PR (#77973).

How

  • Interceptor's "new block" branch captures the previous-tick parent + sibling order to compute anchorClientId (null = first child) and parentClientId (null = root).
  • Top-level filter: only the top-level insertion is tagged; descendants ride along inside the captured block snapshot.
  • Provider apply branches on block-insert-after: clears marker. Reject dispatches removeBlock with bypass.

Testing

  • 136 unit tests pass. Lint clean.
  • For full-stack testing instructions, see the foundations PR (#77967).

Stack

  1. #77967 — Schema v2 bump (foundations)
  2. #77968 — Capture block-remove (mechanism)
  3. #77970 — Render block-remove preview (UI)
  4. #77971 — Capture block-insert-after (mechanism)
  5. #77973 — Render block-insert-after preview (UI)
  6. #77978 — Capture block-move (mechanism)
  7. #77979 — Render block-move preview (UI)

Refs #77434, #73411.

@github-actions github-actions Bot added the [Package] Editor /packages/editor label May 5, 2026
@github-actions

github-actions Bot commented May 5, 2026

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: adamsilverstein <adamsilverstein@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@github-actions

github-actions Bot commented May 5, 2026

Copy link
Copy Markdown

Size Change: +175 B (0%)

Total Size: 7.52 MB

📦 View Changed
Filename Size Change
build/scripts/editor/index.min.js 485 kB +175 B (+0.04%)

compressed-size-action

@adamsilverstein adamsilverstein added [Feature] Notes Phase 3 of the Gutenberg roadmap around block commenting [Status] In Progress Tracking issues with work in progress [Type] Feature New feature to highlight in changelogs. labels May 5, 2026
@github-actions

github-actions Bot commented May 5, 2026

Copy link
Copy Markdown

Flaky tests detected in b396353.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/28184699151
📝 Reported issues:

@adamsilverstein adamsilverstein force-pushed the suggest-mode-6a-remove-ui branch from f859323 to 53bf7fa Compare June 17, 2026 21:12
@adamsilverstein adamsilverstein force-pushed the suggest-mode-6b-insert-mechanism branch from 9a1fb2d to 4cd8b0d Compare June 17, 2026 21:12
@adamsilverstein adamsilverstein force-pushed the suggest-mode-6a-remove-ui branch from 53bf7fa to f070644 Compare June 17, 2026 21:20
@adamsilverstein adamsilverstein force-pushed the suggest-mode-6b-insert-mechanism branch from 4cd8b0d to e2f987d Compare June 17, 2026 21:20
Inserts in Suggest mode now flow through the apply-and-tag pipeline:
the block stays at its inserted position, the metadata.suggestion =
pending-insert marker drives the visual treatment (UI ships in a
follow-up), and auto-save persists a block-insert-after operation
with anchor + parent context. Apply just clears the marker (the
block is already in the tree); Reject runs removeBlock to undo.

The interceptor's "new block" branch now captures the previous-tick
parent + sibling order to compute anchorClientId (null = first child)
and parentClientId (null = root). Descendants of another new block —
a Group with nested children fires multiple new-block entries in one
tick — are filtered out so only the top-level insertion is tagged;
the descendants ride along inside the captured block snapshot.

Refs #77434.
A `removeBlock` dispatch in Suggest mode runs through the
apply-and-tag flow: re-insert the subtree at its previous position,
tag the top with `metadata.suggestion = pending-remove`, and write a
`block-remove` op into the overlay. The post-handler used to call
`snapshot.delete` on the removed clientIds — fine in isolation, but
once the new-block branch (this PR) starts tagging unfamiliar blocks
as `pending-insert`, any follow-up subscribe fire (a YJS sync echo,
an unrelated dispatch, or a follow-up tick drained by React's
batching) finds the re-inserted block missing from the snapshot,
routes it through that branch, and overwrites both the marker and
the persisted structural op with the insert pair.

Re-seed `snapshot` from the live attributes instead. The pending-
remove marker is in `metadata.suggestion`, which is already a member
of `SYSTEM_METADATA_KEYS`, so the re-seeded baseline keeps the
marker invisible to subsequent diffs without leaking it into the
user-pending overlay.

Refs #77434.
The block-insert-after apply branch only cleared the pending-insert
marker on the live block, on the assumption that the live block
already carried the suggested values. That holds on the suggester's
own client — but the suggester's interceptor diverts every post-
insertion edit into the overlay and reverts the live attributes,
so collaborators (and the suggester after a reload) see the live
block in its captured-at-insertion shape: typically an empty
paragraph. After Apply, the marker disappears but the block stays
empty, which reads as "the inserted block didn't appear."

Fold the payload's attribute-set ops into the apply payload along
with the marker clear: `applyOperations` produces the merged
attributes, `clearSuggestionMarkerAttributes` strips the marker
from the result, and the two are spread together for a single
`updateBlockAttributes` dispatch. The marker-clear path in
`adoptSystemMetadata` keeps the dispatch from looping back through
the interceptor.

Refs #77434.
…gging

Rejecting a pending-insert suggestion dispatches a `removeBlock` to
undo the insert. When that lands on a peer client through sync,
batched with the marker-clearing `updateBlockAttributes`, the
removal-detection branch was treating the disappearance as a fresh
user delete — re-inserting the block and tagging it pending-remove.
That re-insert bounced back through sync and undid the reject on the
rejecting client a moment after they clicked.

Extend the apply-landing check to also recognize `pending-insert` in
the previous-tick tree snapshot. The marker presence means the
removal is the reject landing; adopt it.
The conflict check compares each attribute-set op's `before` against the
live block's current attribute. For an inserted block the overlay
baseline is `{}`, so every attribute-set op rides on `before: null`.
On the accepting client the inserted block already carries the typed
content, so the comparison reads as a divergence and the apply flow
opens a 'This block has changed' dialog before every Insert apply.

Inserted blocks have no pre-existing attributes to overwrite — the
attribute-set ops describe the new block's content, not concurrent
edits. Short-circuit `hasAttributeConflict` to false when the payload
carries a `block-insert-after` structural op, and add a regression
test.
@adamsilverstein adamsilverstein force-pushed the suggest-mode-6a-remove-ui branch from f070644 to 4ef0475 Compare June 18, 2026 06:29
@adamsilverstein adamsilverstein force-pushed the suggest-mode-6b-insert-mechanism branch from e2f987d to 7925cae Compare June 18, 2026 06:31
Clicking the default block appender (or the empty canvas below the last
block) inserts an unmodified default paragraph. In Suggest mode the store
interceptor's new-block branch tagged that empty block 'pending-insert'
and wrote a block-insert-after op immediately, surfacing an 'Insert
block' suggestion for a block the user had not put anything into.

Defer the insertion suggestion while the new block is still an unmodified
default block: skip it without recording a snapshot so the next
interceptor fire — once the block has content — re-enters the new-block
branch and registers the insertion. This way a suggestion is only created
once the user actually types into the block.

Add an e2e test covering the empty-appender case and the type-to-suggest
follow-through.

(cherry picked from commit c63392f)
adamsilverstein added a commit that referenced this pull request Jun 24, 2026
…tent

Clicking the default block appender inserts an unmodified default
paragraph via insertDefaultBlock. In Suggest mode that empty block
incorrectly became an Insert block suggestion on its own. Guard the
store interceptor's new-block branch with isUnmodifiedDefaultBlock so
the insertion is only recorded once the block has content, and skip
without recording a snapshot so a later fire re-enters the branch.

Ports the fix already present on the combined branch (#78994) and the
structural stack (#77971) to the inline-suggestions base so #79282
matches. Adds the matching e2e regression test.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] Notes Phase 3 of the Gutenberg roadmap around block commenting [Package] Editor /packages/editor [Status] In Progress Tracking issues with work in progress [Type] Feature New feature to highlight in changelogs.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant